package com.analyse.stock.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.analyse.stock.constant.ApiConstant;
import com.analyse.stock.constant.StockConstant;
import com.analyse.stock.enums.Sentiment;
import com.analyse.stock.mapper.BoardIndexDailyMapper;
import com.analyse.stock.model.BoardCategoryModel;
import com.analyse.stock.model.BoardIndexDailyModel;
import com.analyse.stock.model.IndexInfoModel;
import com.analyse.stock.service.IBoardCategory;
import com.analyse.stock.service.IBoardIndexDaily;
import com.analyse.stock.service.IIndexInfo;
import com.analyse.stock.utils.HttpUtil;
import com.analyse.stock.utils.MarketSentimentAnalyzer;
import com.analyse.stock.utils.StockAnalyzer;
import com.analyse.stock.utils.StockStringUtil;
import com.analyse.stock.vo.FinanceDataVO;
import com.analyse.stock.vo.MarketSentimentVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.ta4j.core.BarSeries;
import org.ta4j.core.indicators.SMAIndicator;
import org.ta4j.core.indicators.helpers.ClosePriceIndicator;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class BoardIndexDailyService extends ServiceImpl<BoardIndexDailyMapper, BoardIndexDailyModel> implements IBoardIndexDaily {

    @Autowired
    private IBoardCategory boardCategory;

    @Autowired
    private IIndexInfo indexInfo;

    @Override
    public Integer pullBoardDailyList(String boardCodes) {
        List<BoardCategoryModel> boardList = boardCategory.getBoardCategoryList(boardCodes);
        if(CollUtil.isEmpty(boardList)){
            return 0;
        }
        AtomicInteger num = new AtomicInteger(0);
        for(BoardCategoryModel model : boardList){
            long time = System.currentTimeMillis()*1001;
            try {
                String url = StrUtil.format(ApiConstant.BOARD_INDEX_DAILY_URL,String.format("%s.%s","90",model.getBoardCode()),time);
                String result = HttpUtil.sendGet(url,"*/*", StockConstant.UTF8,6000L);
                if(StringUtils.isBlank(result)){
                    continue;
                }
                JSONObject jsonObject = JSONObject.parseObject(result);
                if(jsonObject.getInteger("rc") != 0 || Objects.isNull(jsonObject.get("data"))){
                    continue;
                }
                FinanceDataVO dataVO = StockStringUtil.getObject(jsonObject.getString("data"), FinanceDataVO.class);
                log.info("## 板块:{}, 开始解析 最新的二级板块分类数据-----",model.getBoardName());
                BoardIndexDailyModel model1 = BoardIndexDailyModel.transBoardIndexDailyModel(dataVO,0,model.getBoardCode());
                if(Objects.isNull(model1)){
                    continue;
                }
                super.save(model1);
                num.incrementAndGet();
            }catch (Exception ex){
                log.error("## 板块:{}, 获取二级板块分类数据出错 error:{}-----",model.getBoardName(),ex.getMessage(),ex);
            }
        }
        return num.get();
    }

    @Override
    public Integer pullIndexDailyList(String indexCodes) {
        List<IndexInfoModel> indexList = indexInfo.getIndexList(indexCodes);
        if(CollUtil.isEmpty(indexList)){
            return 0;
        }
        AtomicInteger num = new AtomicInteger(0);
        for(IndexInfoModel model : indexList){
            long time = System.currentTimeMillis()*1001;
            try {
                BoardIndexDailyModel model1 = this.getBoardIndexDailyModel(model, time);
                if (Objects.isNull(model1)){
                    continue;
                }
                List<BoardIndexDailyModel> models = this.baseMapper.getBoardIndexDailyList(model1);
                if(CollUtil.isEmpty(models)){
                    super.save(model1);
                }else{
                    model1.setId(models.get(0).getId());
                    super.updateById(model1);
                }
                num.incrementAndGet();
            }catch (Exception ex){
                log.error("## 指数:{}--{}, 获取指数详情出错 error:{}-----",
                        model.getIndexCode(),model.getIndexName(),ex.getMessage(),ex);
            }
        }
        return num.get();
    }


    private BoardIndexDailyModel getBoardIndexDailyModel(IndexInfoModel model, long time) {
        String url = StrUtil.format(ApiConstant.BOARD_INDEX_DAILY_URL, String.format("%s.%s", model.getMarkCode(), model.getIndexCode()), time);
        String result = HttpUtil.sendGet(url, "*/*", StockConstant.UTF8, 6000L);
        if (StringUtils.isBlank(result)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject.getInteger("rc") != 0 || Objects.isNull(jsonObject.get("data"))) {
            return null;
        }
        FinanceDataVO dataVO = StockStringUtil.getObject(jsonObject.getString("data"), FinanceDataVO.class);
        BoardIndexDailyModel model1 = BoardIndexDailyModel.transBoardIndexDailyModel(dataVO, 1, model.getIndexCode());
        if (Objects.isNull(model1)) {
            return null;
        }
        log.info("## 指数:{}--{},     {} ，    涨跌：{}%-----",
                model.getIndexCode(), model.getIndexName(),model1.getPrice(),model1.getUpDownPercent());
        return model1;
    }

    @Override
    public SMAIndicator getIndexSMAValue(String code,Integer codeType,Integer day,String startDate){
        LambdaQueryWrapper<BoardIndexDailyModel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BoardIndexDailyModel::getCode,code);
        wrapper.eq(BoardIndexDailyModel::getCodeType,codeType);
        wrapper.ge(BoardIndexDailyModel::getTradeDate,startDate);
        List<BoardIndexDailyModel> models = super.list(wrapper);
        // 构建时间序列
        BarSeries series = StockAnalyzer.createIndexSeries(models,"INDEX_SMA"+day);
        // 使用收盘价计算短期和长期 SMA
        ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
        return new SMAIndicator(closePrice, day);
    }

    @Override
    public Sentiment sentimentAnalyzer(String code,Integer codeType){
        String dateStr = DateUtil.format(DateUtil.offsetDay(DateUtil.date(),-1), DatePattern.NORM_DATE_FORMAT);
        LambdaQueryWrapper<BoardIndexDailyModel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BoardIndexDailyModel::getCode,code);
        wrapper.eq(BoardIndexDailyModel::getCodeType,codeType);
        wrapper.ge(BoardIndexDailyModel::getTradeDate,dateStr);
        List<BoardIndexDailyModel> models = super.list(wrapper);
        if(CollUtil.isEmpty(models)){
            return Sentiment.NEUTRAL;
        }
        int upCount = 0;           // 上涨家数
        int downCount = 0;         // 下跌家数
        BigDecimal mainNetFlow = BigDecimal.ZERO;    // 主力净流入资金（单位：亿）
        BigDecimal totalAmt = BigDecimal.ZERO;    // 当前总成交额（单位：亿）
        BigDecimal previousAmt = BigDecimal.ZERO; // 昨日总成交额（单位：亿）
        // 示例数据：上涨家数、下跌家数、主力净流入（亿）、当前成交额（亿）、昨日成交额（亿）
        for(BoardIndexDailyModel model : models){
            //昨日
            String date = DateUtil.format(model.getTradeDate(), DatePattern.NORM_DATE_FORMAT);
            if(dateStr.equalsIgnoreCase(date)){
                previousAmt = previousAmt.add(model.getTradeAmount());
            }else{
                upCount += model.getUpStockCount();
                downCount += model.getDownStockCount();
                mainNetFlow = mainNetFlow.add(model.getMainAmt());
                totalAmt = totalAmt.add(model.getTradeAmount());
            }
        }
        BigDecimal mainNetFlow2 = mainNetFlow.divide(new BigDecimal(100000000),2, RoundingMode.HALF_UP);
        BigDecimal totalAmt2 = totalAmt.divide(new BigDecimal(100000000),2, RoundingMode.HALF_UP);
        BigDecimal previousAmt2 = previousAmt.divide(new BigDecimal(100000000),2, RoundingMode.HALF_UP);
        MarketSentimentVO marketData = new MarketSentimentVO(upCount,
                downCount, mainNetFlow2.doubleValue(), totalAmt2.doubleValue(), previousAmt2.doubleValue());
        // 分析市场情绪
        Sentiment sentiment = MarketSentimentAnalyzer.analyzeSentiment(marketData);
        // 输出结果
        log.info("### 今日:{},市场情绪：{} ### ",DateUtil.format(DateUtil.date(), DatePattern.NORM_DATE_FORMAT),sentiment.getDesc());
        return sentiment;
    }
}
